package test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import util.Pair;
import util.Timer;
import dd.discrete.ADD;
import dd.discrete.DD;
import mdp.id.ADDHandler;
import mdp.id.RDDL2DD.DEBUG;
import mdp.id.RDDL2DD.ORDER;

public class testExpectation {

	private static final double density = 0.9;

	private static int makeRandomADD(ADD context, ArrayList<Integer> order, final double density, 
			final boolean BDD) {
		//pick random variable
		//recurse
		//at leaf get random double
		return makeRandomADDInt(context, order, density, 0, BDD);
	}

	private static int makeRandomADDInt(ADD context, ArrayList<Integer> vars, 
			final double density, int index, final boolean BDD) {
		if( index == vars.size() ){
			return context.getConstantNode(BDD ? (Math.random() < density ? 0.0 : 1.0) : Math.random());
		}
		
		if( Math.random() < density ){
			int high = makeRandomADDInt(context, vars, density, index+1, BDD);
			int low = makeRandomADDInt(context, vars, density, index+1, BDD);
			
			int id = vars.get(index);
			
			int lowbr = context.getVarNode(id, 1.0d, 0.0d);
			
			int highbr = context.getVarNode(id, 0.0d, 1.0d);

			low = context.applyInt(low, lowbr, DD.ARITH_PROD );
			high = context.applyInt(high, highbr, DD.ARITH_PROD );
			
			return context.applyInt(low, high, DD.ARITH_SUM );
		}
		return makeRandomADDInt(context, vars, density, index+1, BDD);
	}

	public static void main(String[] args) {
		
		//for a given domain and instance
		String domain = "./rddl/sysadmin_mdp.rddl";
		String inst = "./rddl/sysadmin_star_6_1.rddl";

		ADDHandler handler = new ADDHandler(DEBUG.PROBLEM_INFO, ORDER.GUESS);
		handler.buildFromFile(domain, inst);
		
		int NTRIALS = 1000;

		ArrayList<Integer> sumOrd = handler.getSumOrder();
		ArrayList<Integer> order = new ArrayList<Integer>();
		for( int i : sumOrd ){
			String name =  handler.getVarName(i);
			System.out.println(name);
			order.add( handler.toContextID( name ) );
		}
		
		for( int t = 0 ; t < NTRIALS; ++t ){
			//generate random ADD with those vars
			int add = makeRandomADD(handler._context, order, density, false);
			//prime it
			
			int v1 = add;
			int v2 = add;
			System.out.println(sumOrd);
			
			for( int i : sumOrd ){
				
				int oldv1 = v1;
				
				Timer time = new Timer();
				v1 = handler.computeExpectation(v1, i, null, true, add, v1, v2, oldv1);
				handler.flushCaches(false, v1, v2, add, oldv1);
				System.out.print(time.GetTimeSoFarAndResetInMinutes()+ " " );
				
				int dual = handler.getDualDiagram(i, null);
				v2 = handler._context.applyInt(v2, dual, DD.ARITH_PROD);
				String name = handler.getVarName(i);
				v2 = handler._context.opOut(v2, handler.toContextID(name), DD.ARITH_SUM);
				v2 = handler.ConstrainThis(v2, null, true, add, v1, oldv1);
				
				handler.flushCaches(false, oldv1, v1, v2, add);
				System.out.println(time.GetTimeSoFarAndResetInMinutes());
				System.out.println();
				
				if( handler.fix(handler._context.applyInt(v1, v2, DD.ARITH_MINUS)) != handler.DD_ZERO ){
					System.err.println("difference after E " + name);
					
					handler.showGraph(dual, v1, v2, oldv1);
					System.out.println();
					try {
						System.in.read();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
			}
			//compute expectation - current method
			
			//for each cpt var get dual diagram for each
			//and compute expectation over each 
			//verify same result
			
			if( v1 != v2 ){
				System.err.println("difference");
				handler.showGraph(add, v1, v2);
				try {
					System.in.read();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}else{
				System.out.println(handler.getSize(v1, v2));
			}
		}
	}
	
}
